﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SharpPcap;
using SharpPcap.LibPcap;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Collections;
using PacketDotNet;

namespace RelatedFireWall
{
    public partial class RelatedFireWall : Form
    {
        private LibPcapLiveDeviceList devices;
        private PcapDevice device;
        private delegate void ActionReceiveData(CaptureEventArgs e);
        private easySorter sorter;
        const Int32 PROCESS_ALL_ACCESS = 0x1F0FFF;
        const Int32 PROCESS_QUERY_INFORMATION = 0x00000400;
        const Int32 PROCESS_VM_READ = 0x0010;
        const Int32 PROCESS_VM_WRITE = 0x0020;
        [DllImport("Kernel32.dll", EntryPoint = "QueryFullProcessImageNameW", CharSet = CharSet.Auto)]
        extern static Int32 QueryFullProcessImageNameW(Int32 hProcess, UInt32 flags, char[] nameList, ref UInt32 nameLen);
        [DllImport("kernel32.dll")]
        public static extern Int32 OpenProcess(Int32 DesiredAccess, bool bInheritHandle, Int32 ProcessId);
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool CloseHandle(Int32 hObject);
        [DllImport("kernel32.dll")]
        public static extern Int32 GetLastError();
        private int packetCount = 0;
        public RelatedFireWall()
        {
            InitializeComponent();
            sorter = new easySorter();
            this.Running_Processes.ListViewItemSorter = sorter;
            sorter.SortOrder = SortOrder.Ascending;
            tcpFilter.Checked = true;
        }

        private void EasyFireWallSniffer_Load(object sender, EventArgs e)
        {
            stopCapture.Enabled = false;
        }

        private void device_OnPacketArrival(Object sender,CaptureEventArgs args)
        {
            new Thread(() => 
            { 
                ActionReceiveData actionReceiveData = new ActionReceiveData(receiveData);
                CaptureEventArgs e = args;
                Invoke(actionReceiveData, e);
            }).Start();
        }
        private String byteToHexString(byte[] data)
        {
            String returnStr = "";
            for (int i = 0; i < data.Length; i++)
            {
                returnStr += data[i].ToString("X2");

            }
            return returnStr;
        }
        private void receiveData(CaptureEventArgs e)
        {
            DateTime time = e.Packet.Timeval.Date;
            int len = e.Packet.Data.Length;
            String packetType = null;
            TcpPacket tcpPacket;
            UdpPacket udpPacket;
            Byte[] data;
            System.Net.IPAddress srcIp=null, dstIp=null;
            int srcPort=0, dstPort=0;
            var packet = PacketDotNet.Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
            data = e.Packet.Data;
            int sign = 0;
            if (device.Filter == "ip and tcp")
            {
                packetType = "Tcp";
                tcpPacket = PacketDotNet.TcpPacket.GetEncapsulated(packet);
                var ipPacket = (PacketDotNet.IpPacket)tcpPacket.ParentPacket;
                srcIp = ipPacket.SourceAddress;
                dstIp = ipPacket.DestinationAddress;
                srcPort = tcpPacket.SourcePort;
                dstPort = tcpPacket.DestinationPort;
            }
            else if (device.Filter == "udp")
            {
                packetType = "Udp";
                udpPacket = PacketDotNet.UdpPacket.GetEncapsulated(packet);
                var ipPacket = (PacketDotNet.IpPacket)udpPacket.ParentPacket;
                srcIp = ipPacket.SourceAddress;
                dstIp = ipPacket.DestinationAddress;
                srcPort = udpPacket.SourcePort;
                dstPort = udpPacket.DestinationPort;
            }
            else
            {
                sign = 1;
            }
            packetCount++;
            this.receivedData.Text += "第" + packetCount + "个数据包相关参数:"+" 包类型:"+packetType;
            this.receivedData.Text += " Packet length:"+len+" PacketReceivedTime:"+time;
            if (sign == 0)
            {
                this.receivedData.Text += " srcIp:" + srcIp.ToString() + " dstIp:" + dstIp.ToString();
                this.receivedData.Text += " srcPort:" + srcPort + " dstPort:" + dstPort; 
            }
            this.receivedData.Text += " 包内容十六进制显示为:" + "\r\n";
            receivedData.Text +=packet.PrintHex()+ "\r\n";
        }
        private void addAllPID()
        {
            List<String> infoList = new List<String>();
            List<String> nameList = new List<String>();
            System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo();
            System.Diagnostics.Process pro = new System.Diagnostics.Process();
            pro.StartInfo.FileName = "cmd";
            pro.StartInfo.UseShellExecute = false;
            pro.StartInfo.RedirectStandardInput = true;
            pro.StartInfo.RedirectStandardOutput = true;
            pro.StartInfo.RedirectStandardError = true;
            pro.StartInfo.CreateNoWindow = true;
            pro.Start();
            pro.StandardInput.WriteLine("netstat -anob");
            pro.StandardInput.WriteLine("exit");
            Regex reg = new Regex("\\s+", RegexOptions.Compiled);
            string line = null;
            infoList.Clear();
            nameList.Clear();
            while ((line = pro.StandardOutput.ReadLine()) != null)
            {
                line = line.Trim();
                if (line.StartsWith("TCP", StringComparison.OrdinalIgnoreCase))
                {
                    line = reg.Replace(line, ",");
                    infoList.Add(line);
                }
                if (line.StartsWith("UDP", StringComparison.OrdinalIgnoreCase))
                {
                    line = reg.Replace(line, ",");
                    infoList.Add(line);
                }
                if (line.StartsWith("["))
                {
                    line = line.Replace("[", "");
                    line = line.Replace("]", "");
                    nameList.Add(line);
                }
                else if (line.StartsWith("无法"))
                {
                    nameList.Add("");
                }
            }
            pro.Close();
            for (int i = 0; i < infoList.Count&&i<nameList.Count; i++)
            {
                if (infoList[i].ToString().Split(',')[0] == "TCP")
                {
                    ListViewItem listItem = new ListViewItem();
                    listItem.Text = infoList[i].ToString().Split(',')[0];
                    listItem.SubItems.Add(infoList[i].Split(',')[1]);
                    listItem.SubItems.Add(infoList[i].Split(',')[2]);
                    listItem.SubItems.Add(infoList[i].Split(',')[3]);
                    listItem.SubItems.Add(infoList[i].Split(',')[4]);
                    listItem.SubItems.Add(nameList[i]);
                    this.Running_Processes.Items.Add(listItem);
                }
                else if (infoList[i].ToString().Split(',')[0] == "UDP")
                {
                    ListViewItem listItem = new ListViewItem();
                    listItem.Text = infoList[i].ToString().Split(',')[0];
                    listItem.SubItems.Add(infoList[i].Split(',')[1]);
                    listItem.SubItems.Add(infoList[i].Split(',')[2]);
                    listItem.SubItems.Add("");
                    listItem.SubItems.Add(infoList[i].Split(',')[3]);
                    listItem.SubItems.Add(nameList[i]);
                    this.Running_Processes.Items.Add(listItem);
                }
            }
        }
        private string GetFullPathByPid(Int32 pid)
        {
            Int32 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid);
            char[] buf = new char[512];
            UInt32 len = 512;
            QueryFullProcessImageNameW(hProcess, 0, buf, ref len);
            CloseHandle(hProcess);
            string nameList = new string(buf, 0, (int)len);
            return nameList;
        }
        private void callCmdAddRules(String type,String mode)
        {
            for (int i = 0; i < this.Running_Processes.SelectedItems.Count; i++)
            {
                string port = this.Running_Processes.SelectedItems[i].SubItems[4].Text;
                string inname = "\""+ type + this.Running_Processes.SelectedItems[i].SubItems[5].Text + "\"";
                string proto = this.Running_Processes.SelectedItems[i].SubItems[0].Text;
                string str = " netsh advfirewall firewall add rule name=" + inname + " dir=" + mode + " action=" + type + " protocol=" + proto + " localport= " + port;
                callCmdExecutive(str);
            }
        }
        private void callCmdAddRulesOnProgram(String type,String mode)
        {
            for (int i = 0; i < this.Running_Processes.SelectedItems.Count; i++)
            {
                string path = "\"" + GetFullPathByPid(Convert.ToInt32(Running_Processes.SelectedItems[i].SubItems[4].Text)) + "\"";
                string inname = "\"" +type + Running_Processes.SelectedItems[i].SubItems[5].Text + "\"";
                string str = "netsh advfirewall firewall add rule name=" + inname + "  dir=" + mode + " program=" + path + " action="+type;
                callCmdExecutive(str);
            }
        }
        private void callCmdDeleteRules(String type)
        {
            for (int i = 0; i < this.Running_Processes.SelectedItems.Count; i++)
            {
                string inname = "\"" + type + this.Running_Processes.SelectedItems[i].SubItems[5].Text + "\"";
                string str = "netsh advfirewall firewall delete rule name=" + inname;
                callCmdExecutive(str);
            }
        }
        private void callCmdDeleteRulesOnProgram(String type)
        {
            for (int i = 0; i < this.Running_Processes.SelectedItems.Count; i++)
            {
                string inname = "\"" + type + Running_Processes.SelectedItems[i].SubItems[5].Text + "\"";
                string str = "netsh advfirewall firewall delete rule name=" + inname;
                callCmdExecutive(str);
            }
        }
        private void callCmdDeleteAllRules()
        {
            string str = "netsh advfirewall firewall delete rule name=all";
            callCmdExecutive(str);
        }
        private void callCmdExecutive(String str)
        {
            System.Diagnostics.Process pro = new System.Diagnostics.Process();
            pro.StartInfo.FileName = "cmd.exe";
            pro.StartInfo.UseShellExecute = false;
            pro.StartInfo.RedirectStandardInput = true;
            pro.StartInfo.RedirectStandardOutput = true;
            pro.StartInfo.RedirectStandardError = true;
            pro.StartInfo.CreateNoWindow = true;
            pro.Start();
            pro.StandardInput.WriteLine(str + "&exit");
            pro.StandardInput.AutoFlush = true;
            string info = pro.StandardOutput.ReadToEnd();
            MessageBox.Show(info);
            pro.WaitForExit();
            pro.Close();
        }
        private void getAdapter_Click(object sender, EventArgs e)
        {
            Network_Cards.Items.Clear();
            devices = LibPcapLiveDeviceList.Instance;
            if (devices.Count < 1)
            {
                MessageBox.Show("没有网络适配器");
            }
            else
            {
                foreach (var device in devices)
                {
                    Network_Cards.Items.Add(device.Interface.FriendlyName);
                }
            }
        }

        private void startCapture_Click(object sender, EventArgs e)
        {
            device = devices[Network_Cards.SelectedIndex];
            device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival);
            int timeout = 2333;
            device.Open(DeviceMode.Promiscuous, timeout);
            if (tcpFilter.Checked && !udpFilter.Checked)
            {
                device.Filter = "ip and tcp";
            }
            else if (!tcpFilter.Checked && udpFilter.Checked)
            {
                device.Filter = "udp";
            }
            else
            {
                device.Filter = null;
            }
            device.StartCapture();
            startCapture.Enabled = false;
            stopCapture.Enabled=true;
            Network_Cards.Enabled = false;
            udpFilter.Enabled = false;
            tcpFilter.Enabled = false;
        }

        private void stopCapture_Click(object sender, EventArgs e)
        {
            device.StopCapture();
            stopCapture.Enabled = false;
            startCapture.Enabled = true;
            device.Close();
            Network_Cards.Enabled = true;
            udpFilter.Enabled = true;
            tcpFilter.Enabled = true;
        }
        private void getAllPID_Click(object sender, EventArgs e)
        {
            this.Running_Processes.Items.Clear();
            addAllPID();
        }

        private void lockTargetPID_Click(object sender, EventArgs e)
        {
            if (typeAccess.SelectedItem != null && modeAccess.SelectedItem != null)
                callCmdAddRules(typeAccess.Items[typeAccess.SelectedIndex].ToString(), modeAccess.Items[modeAccess.SelectedIndex].ToString());
            else
                MessageBox.Show("请确保选择了in、out中的一个和block、allow中的一个");
        }

        private void unlockTargetPID_Click(object sender, EventArgs e)
        {
            if (typeAccess.SelectedItem != null)
                callCmdDeleteRules(typeAccess.Items[typeAccess.SelectedIndex].ToString());
            else
                MessageBox.Show("请确保选择了in、out中的一个");
        }

        private void justReset_Click(object sender, EventArgs e)
        {
            string str = " netsh advfirewall reset";
            callCmdExecutive(str);
        }

        private void Running_Processes_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (e.Column == this.sorter.SortColumn)
            {
                if (this.sorter.SortOrder == SortOrder.Ascending)
                    this.sorter.SortOrder = SortOrder.Descending;
                else
                if (this.sorter.SortOrder == SortOrder.Descending)
                    this.sorter.SortOrder = SortOrder.Ascending;
                else
                    return;
            }
            else
            {
                this.sorter.SortColumn = e.Column;
            }
            this.Running_Processes.Sort();
        }

        private void lockTargetProgram_Click(object sender, EventArgs e)
        {
            if (typeAccess.SelectedItem != null && modeAccess.SelectedItem != null)
                callCmdAddRulesOnProgram(typeAccess.Items[typeAccess.SelectedIndex].ToString(), modeAccess.Items[modeAccess.SelectedIndex].ToString());
            else
                MessageBox.Show("请确保选择了in、out中的一个和block、allow中的一个");
        }

        private void unlockTargetProgram_Click(object sender, EventArgs e)
        {
            if(typeAccess.SelectedItem!=null)
            callCmdDeleteRulesOnProgram(typeAccess.Items[typeAccess.SelectedIndex].ToString());
            else
                MessageBox.Show("请确保选择了in、out中的一个");
        }

        private void justResetAllRules_Click(object sender, EventArgs e)
        {
            callCmdDeleteAllRules();
        }

        private void openFireWall_Click(object sender, EventArgs e)
        {
            string str = "netsh advfirewall set allprofiles state on";
            callCmdExecutive(str);
            this.openFireWall.Enabled = false;
            this.shutdownFireWall.Enabled = true;
        }

        private void shutdownFireWall_Click(object sender, EventArgs e)
        {
            string str = "netsh advfirewall set allprofiles state off";
            callCmdExecutive(str);
            this.openFireWall.Enabled = true;
            this.openFireWall.Enabled = false;
        }

        private void tcpFilter_CheckedChanged(object sender, EventArgs e)
        {
            if (!tcpFilter.Checked && !udpFilter.Checked)
                tcpFilter.Checked = true;
        }

        private void udpFilter_CheckedChanged(object sender, EventArgs e)
        {
            if (!tcpFilter.Checked && !udpFilter.Checked)
                udpFilter.Checked = true;
        }
    }
    public class easySorter : IComparer
    {
        private Comparer comparer;
        private int sortColumn;
        private SortOrder sortOrder;
        public easySorter()
        {
            sortColumn = 0;
            sortOrder = SortOrder.None;
            comparer = Comparer.Default;
        }
        public int SortColumn
        {
            get { return sortColumn; }
            set { sortColumn = value; }
        }
        public SortOrder SortOrder
        {
            get { return sortOrder; }
            set { sortOrder = value; }
        }
        public int Compare(object x, object y)
        {
            int CompareResult;
            ListViewItem itemX = (ListViewItem)x;
            ListViewItem itemY = (ListViewItem)y;
            CompareResult = comparer.Compare(itemX.SubItems[this.sortColumn].Text, itemY.SubItems[this.sortColumn].Text);
            if (this.SortOrder == SortOrder.Ascending)
                return CompareResult;
            else
            if (this.SortOrder == SortOrder.Descending)
                return (-CompareResult);
            else
                return 0;
        }
    }
}
